package com.ming.liteflow.controller;

import com.ming.common.Options;
import com.ming.common.SortBy;
import com.ming.common.beetl.util.Result;
import com.ming.common.beetl.util.StrUtil;
import com.ming.common.dynamic.IvyClassHelper;
import com.ming.common.dynamic.IvyCmpHelper;
import com.ming.common.liteflow.core.dynamic.IvyDynamicClass;
import com.ming.common.liteflow.core.exec.ClassExecUtil;
import com.ming.common.liteflow.core.execption.LiteFlowELException;
import com.ming.common.liteflow.vo.IvyDynamicClassVo;
import com.ming.common.util.ClassFieldUtil;
import com.ming.common.util.FileUtil;
import com.ming.common.util.ResourceUtil;
import com.ming.common.xxljob.annotation.PermissionLimit;
import com.yomahub.liteflow.core.FlowExecutor;
import org.beetl.sql.core.SQLManager;
import org.beetl.sql.core.page.PageResult;
import org.beetl.sql.core.query.LambdaQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.io.File;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/liteflow/dynamic/class")
public class LiteFlowDynamicClassController {

    private static final Logger LOG = LoggerFactory.getLogger(LiteFlowDynamicClassController.class);

    @Resource
    private SQLManager sqlManager;

    @Autowired
    private ResourceLoader resourceLoader;

    @Resource
    private FlowExecutor flowExecutor;

    @PostMapping("/option")
    @PermissionLimit(limit = false)
    public Result<?> option(@RequestBody Map<String,Object> map) throws LiteFlowELException {
        return Result.OK(ClassFieldUtil.getFieldAnnoDescribe(IvyDynamicClass.class, map));
    }

    @PostMapping("/page")
    @PermissionLimit(limit = false)
    public Result<PageResult<IvyDynamicClass>> page(@RequestBody IvyDynamicClassVo vo){
        LambdaQuery<IvyDynamicClass> lambdaQuery = sqlManager.lambdaQuery(IvyDynamicClass.class);
        lambdaQuery.andLike(IvyDynamicClass::getClassId, LambdaQuery.filterLikeEmpty(vo.getClassId()));
        lambdaQuery.andLike(IvyDynamicClass::getClassName, LambdaQuery.filterLikeEmpty(vo.getClassName()));
        lambdaQuery.andLike(IvyDynamicClass::getPackagePath, LambdaQuery.filterLikeEmpty(vo.getPackagePath()));
        lambdaQuery.andEq(IvyDynamicClass::getClassLoaderType, LambdaQuery.filterEmpty(vo.getClassLoaderType()));
        lambdaQuery.andEq(IvyDynamicClass::getClassType, LambdaQuery.filterEmpty(vo.getClassType()));
        Options options = vo.getOptions();
        List<SortBy> sortBy = options.getSortBy();
        for (SortBy sort : sortBy) {
            if ("desc".equalsIgnoreCase(sort.getOrder())) {
                lambdaQuery.desc(StrUtil.camelToSnake(sort.getKey()));
            } else {
                lambdaQuery.asc(StrUtil.camelToSnake(sort.getKey()));
            }
        }
        PageResult<IvyDynamicClass> page = lambdaQuery.page(options.getPage(), options.getItemsPerPage());
        return Result.OK(page);
    }

    @PostMapping("/add")
    @PermissionLimit(limit = false)
    public Result<?> add(@RequestBody IvyDynamicClass item){
        LambdaQuery<IvyDynamicClass> query = sqlManager.lambdaQuery(IvyDynamicClass.class);
        item.setVersion(1);
        handlerIvyDynamicClass(item);
        int i = query.insert(item);
        return Result.OK(i);
    }

    @PostMapping("/update")
    @PermissionLimit(limit = false)
    public Result<Object> update(@RequestBody IvyDynamicClass item){
        item.setVersion(item.getVersion()+1);
        handlerIvyDynamicClass(item);
        int i = sqlManager.updateById(item);
        return Result.OK("更新成功", i);
    }

    @PostMapping("/updateSourceCode")
    @PermissionLimit(limit = false)
    public Result<Object> updateSourceCode(@RequestBody IvyDynamicClass item){
        item.setVersion(item.getVersion()+1);
        handlerIvyDynamicClass(item);
        int i = sqlManager.updateTemplateById(item);
        String root = ClassUtils.getDefaultClassLoader().getResource("").getPath();
        String packagePath = String.join(File.separator,item.getPackagePath().split("\\."));
        String rootPath = root+packagePath;
        FileUtil.removeSameFile(rootPath, item.getSourceClassName());
        return Result.OK("更新成功", i);
    }

    private void handlerIvyDynamicClass(IvyDynamicClass item){
        String sourceCode = item.getSourceCode();
        item.setPackagePath(ClassExecUtil.getPackagePath(sourceCode));
        if(cn.hutool.core.util.StrUtil.isBlank(item.getPackagePath())){
            throw new RuntimeException("源码未设置包路径！");
        }
        item.setSourceCmpId(ClassExecUtil.getCmpId(sourceCode));
        item.setSourceClassName(ClassExecUtil.getClassName(sourceCode));
        item.setClassId(item.getPackagePath()+"."+item.getSourceClassName());
        if(item.getClassType() != null && item.getClassType() == 0){
            item.setIsFallback(null);
        }
    }

    @PostMapping("/delete")
    @PermissionLimit(limit = false)
    public Result<Integer> delete(@RequestBody IvyDynamicClass item){
        LambdaQuery<IvyDynamicClass> lambdaQuery = sqlManager.lambdaQuery(IvyDynamicClass.class);
        lambdaQuery.andEq(IvyDynamicClass::getId, item.getId());
        int i = lambdaQuery.delete();
        return Result.OK("删除成功",i);
    }

    @PostMapping("/codeTemplate")
    @PermissionLimit(limit = false)
    public Result<?> codeTemplate(@RequestBody IvyDynamicClass item){
        if(item.getClassType() == null){
            return Result.error("未选择class类型！");
        }
        if(item.getClassType() == 0){
            return Result.OK(ResourceUtil.getResourceFtl(resourceLoader,"IvyDynamicClass.ftl"));
        }
        String key = item.getClassType() + (item.getIsFallback() == null ? "" : item.getIsFallback().toString());
        String file = null;
        switch (key){
            case "10": file = "IvyDynamicCmpCommon.ftl";break;//普通组件类
            case "20": file = "IvyDynamicCmpSwitch.ftl";break;//选择组件类
            case "30": file = "IvyDynamicCmpIf.ftl";break;//条件组件类
            case "40": file = "IvyDynamicCmpFor.ftl";break;//次数循环组件类
            case "50": file = "IvyDynamicCmpWhile.ftl";break;//条件循环组件类
            case "60": file = "IvyDynamicCmpIterator.ftl";break;//迭代循环组件类
            case "70": file = "IvyDynamicCmpBreak.ftl";break;//退出循环组件类
            case "11": file = "IvyDynamicCmpCommonFallback.ftl";break;//普通组件类
            case "21": file = "IvyDynamicCmpSwitchFallback.ftl";break;//选择组件类
            case "31": file = "IvyDynamicCmpIfFallback.ftl";break;//条件组件类
            case "41": file = "IvyDynamicCmpForFallback.ftl";break;//次数循环组件类
            case "51": file = "IvyDynamicCmpWhileFallback.ftl";break;//条件循环组件类
            case "61": file = "IvyDynamicCmpIteratorFallback.ftl";break;//迭代循环组件类
            case "71": file = "IvyDynamicCmpBreakFallback.ftl";break;//退出循环组件类
            default: break;
        }
        return Result.OK(ResourceUtil.getResourceFtl(resourceLoader,file));
    }

    @PostMapping("/exec/cmp")
    @PermissionLimit(limit = false)
    public Result<?> execCmp(@RequestBody IvyDynamicClassVo item) throws Exception {
        LambdaQuery<IvyDynamicClass> lambdaQuery = sqlManager.lambdaQuery(IvyDynamicClass.class);
        lambdaQuery.andEq(IvyDynamicClass::getId, item.getId());
        IvyDynamicClass dynamicClass = lambdaQuery.single();
        if(!item.getSourceCode().equals(dynamicClass.getSourceCode())){
            dynamicClass.setSourceCode(item.getSourceCode());
        }
//        return Result.OK(ClassExecUtil.execCmp(dynamicClass,item.getSourceCode()));
        return Result.OK(IvyCmpHelper.execCmp(dynamicClass, item.getEl()));
    }

    @PostMapping("/exec/common")
    @PermissionLimit(limit = false)
    public Result<?> execCommon(@RequestBody IvyDynamicClassVo vo) throws Exception {
        return Result.OK(IvyClassHelper.run(vo));
    }
}
